package org.example.slave.bootstrap;

import lombok.RequiredArgsConstructor;
import org.example.slave.channel.MyChannel;
import org.example.slave.connector.mysql.MysqlConnector;
import org.example.slave.enums.PersistenceType;
import org.example.slave.enums.SourceType;
import org.example.slave.event.LogEvent;
import org.example.slave.executor.mysql.curd.MysqlQueryExecutor;
import org.example.slave.fetch.FetcherFactory;
import org.example.slave.packet.ErrPacket;
import org.example.slave.packet.HeaderPacket;
import org.example.slave.packet.RegisterSlaveCommandPacket;
import org.example.slave.packet.execute.ResultSetPacket;
import org.example.slave.parser.ParserFactory;
import org.example.slave.util.MyChannelUtil;
import org.example.slave.util.MysqlCodecUtil;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.List;

/**
 * @author dingrui
 * @since 2022/2/14
 * @description
 */
@Component
@RequiredArgsConstructor
public class Bootstrap {

    private final FetcherFactory fetcherFactory;
    private final ParserFactory parserFactory;

    public void start(SourceType sourceType, PersistenceType persistenceType) throws IOException {
        String host = "127.0.0.1";
        int port = 3306;
        String username = "root";
        String pwd = "19920308";
        MysqlConnector connector = new MysqlConnector(new InetSocketAddress(host, port), username, pwd);
        connector.connect();
        this.updateSettings(connector);
        int binlogCheckSum = this.loadBinlogChecksum(connector);
        this.registerSlave(connector, 9);

    }

    private void updateSettings(MysqlConnector connector) {

    }

    private int loadBinlogChecksum(MysqlConnector connector) {
        ResultSetPacket rs = null;
        try {
            rs = new MysqlQueryExecutor(connector).query("select @@global.binlog_checksum");
        } catch (Exception e) {
            throw e;
        }

        List<String> columnValues = rs.getFieldValues();
        if (columnValues != null && columnValues.size() >= 1 && columnValues.get(0).toUpperCase().equals("CRC32"))
            return LogEvent.BINLOG_CHECKSUM_ALG_CRC32;
        else
            return LogEvent.BINLOG_CHECKSUM_ALG_OFF;
    }

    public void registerSlave(MysqlConnector connector, int slaveId) {
        RegisterSlaveCommandPacket cmd = new RegisterSlaveCommandPacket();
        cmd.setReportHost(connector.getSocketAddress().getAddress().getHostAddress());
        cmd.setReportPasswd(connector.getPwd());
        cmd.setReportUser(connector.getUsername());
        cmd.setServerId(slaveId);
        byte[] cmdBody = cmd.toBytes();

        HeaderPacket header = new HeaderPacket();
        header.setPacketBodyLength(cmdBody.length);
        header.setPacketSequenceNumber((byte) 0x00);
        MyChannel channel = connector.getMyChannel();
        MyChannelUtil.write(channel, header.toBytes(), cmdBody);

        header = MysqlCodecUtil.readHeader(channel, 4);
        byte[] body = MyChannelUtil.readBytes(channel, header.getPacketBodyLength());
        assert body != null;
        if (body[0] < 0) {
            if (body[0] == -1) {
                ErrPacket err = new ErrPacket();
                err.fromBytes(body);
                throw new RuntimeException("err: " + err);
            } else {
                throw new RuntimeException("field_count = " + body[0]);
            }
        }
    }
}
